/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package VocSymbTest2;

import java.util.Iterator;

//import java.util.Iterator;

/**
 *
 * @author StiggieBig
 */
public class NonTerminal extends VocabularySymbol{

	VocabularySymbolSet<Terminal> follow;

	public NonTerminal() {
		super();
		follow = new VocabularySymbolSet<Terminal>();
	}

	public NonTerminal(char nonTermChar, int pos) {
		super(nonTermChar, pos);
		follow = new VocabularySymbolSet<Terminal>();
	}

	//	copy constructor
	public NonTerminal(NonTerminal rhs) {
		super(rhs);
		follow = new VocabularySymbolSet<Terminal>();
		follow = rhs.follow;
	}

	public int SetFollow(Grammar grammar) {
		int numAdditions = 0;
		int totAdditions = 0;
		/*	Source, empty, and end will have to be added as types of SpecialSymbols
		 *  or NonTerminals so the symbols' characters won't have to be hard coded.
		 *  This, as with SetFirst seem amenable to multithreading, will have to 
		 *  look into that. 
		 */
		NonTerminal Source = grammar.allNonTerminals.GetVocSymbFromChar('S');
		SpecialSymbol empty = grammar.allSpecialSymbols.GetVocSymbFromChar('e');
		SpecialSymbol end = grammar.allSpecialSymbols.GetVocSymbFromChar('$');
		Iterator<VocabularySymbol> it1;
		Iterator<VocabularySymbol> it2;
		VocabularySymbol beta;
		VocabularySymbol B;
		do{
			/*	Add end to source.follow and then set additions to 
			 *  zero, since only in the trivial case will additions
			 *  stop with S, and in which case the algorithm should
			 *  stop with that.
			 */
			
			//	If this is Source 'S'
			if(this.compareTo(Source) == 0){
				//	add input right end marker '$' to this.follow
				this.AddToFollow(end);
			}
			/* Per the comment on source.follow add
			 * set numAdditions to zero.
			 */
			
			numAdditions = 0;
			
			/* If there is a production 'this->alphaBbeta', with B a NonTerminal,
			 *  then everything in beta.first except the empty string
			 *  is in B.follow
			 */
			
			//	For each production
			for(GrammarRule nextGramRule : grammar.allGrammarRules){	
				//	if this is the source of the production
				
				
				if(this.compareTo(nextGramRule.GetSource()) == 0){
					
					//	debugging: Why isn't ')' in 'F'.follow?
					//	answer: numAdditions gets set to zero after each call of SetFollows on a
					//	NonTerminal in ProcessFollows while there had been additions 
					//	during that round. When passing numAdditions back one passes zero
					//	instead of the total count of additions during that round, hence
					//	ProcessFollows wasn't reentering the loop when it should have.
					//if(this.GetSymbolChar() == 'E' && nextGramRule.source.GetSymbolChar() == 'E'){
						//System.out.print("Considering GrammarRule: ");
						//nextGramRule.Print();
						//System.out.printf(" with source symbol %c", this.GetSymbolChar());
						//System.out.println("");
					//}
					/*	Check if this production is of the form 'this->alphBbeta'
					 *  with B a nonTerminal
					 */
					
					//	for each VocabularySymbol in the target GrammarString of this GrammarRule
					for (it1 = nextGramRule.GetTarget().iterator(); it1.hasNext();) {
						B = it1.next();
						it2 = it1;
						// if B is a nonterminal
						if(B.IsNonTerm()){
							//  if a string follows B the production is A->alphaBbeta
							if(it2.hasNext()){
								beta = it2.next();
								// debugging: Why isn't ')' in 'F'.follow?
								//if(this.GetSymbolChar() == 'E' && nextGramRule.source.GetSymbolChar() == 'E'){
								//	System.out.printf("The next symbol after %c is %c.\n",B.GetSymbolChar(), beta.GetSymbolChar());
								//}
								//	everything, other than 'empty', in beta.first is in B.follow
								for(Terminal addThis : beta.GetFirst()){
									// debugging: Why isn't ')' in 'F'.follow?
									//if(this.GetSymbolChar() == 'E' && nextGramRule.source.GetSymbolChar() == 'E'){
										//beta.GetFirst().Print();
										//System.out.printf("Attempting to add %c in %c.first to %c.follow.\n",
										//		addThis.GetSymbolChar(),
										//		beta.GetSymbolChar(),
										//		B.GetSymbolChar());
									//}
									//	check if the Terminal addThis is 'empty'
									if(addThis.compareTo(empty) != 0){
										//  add addThis to B.follow
										if(((NonTerminal)B).AddToFollow(addThis)){
											// there have been additions
											numAdditions++;
											totAdditions++;
										}
									}
								}
								//  if first.beta contains the empty string add 
								if(beta.GetFirst().isVocSymbElem(empty)){
									//	everything from this.follow to B.follow
									for(Terminal addThis : this.follow){
										//	add addThis to B.follow
										if(((NonTerminal)B).AddToFollow(addThis)){
											numAdditions++;
											totAdditions++;
										}
									}
								}
							}else{
								//  The production is of the form A->alphaB, add everything from follow(A)to follow(B)
								for(Terminal addThis : this.follow){
									// debugging: Why isn't ')' in 'F'.follow?
									//if(this.GetSymbolChar() == 'E' && nextGramRule.source.GetSymbolChar() == 'E'){
									//	this.GetFollow().Print();
									//	System.out.printf("Attempting to add %c in %c.follow to %c.follow.\n",
									//			addThis.GetSymbolChar(),
									//			this.GetSymbolChar(),
									//			B.GetSymbolChar());
									//}
									//	add addThis to B.follow
									if(((NonTerminal)B).AddToFollow(addThis)){
										numAdditions++;
										totAdditions++;
									}
								}
							}
						}
					}
				}
			}
		}while(numAdditions != 0);
		return totAdditions;
	}

	public boolean AddToFollow(Terminal terminal){
		return follow.add(terminal);
	}
	
	public VocabularySymbolSet<Terminal> GetFollow() {
		return follow;
	}
}
